from random import choices
from django.db.models.signals import post_save
from django.dispatch import receiver
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
from django.db import models
from django.contrib.auth.models import AbstractUser
"""
post_save信号会在UserProfile保存后触发

get_dirty_fields()检查哪些字段被修改

async_to_sync将异步调用转换为同步

group_send向指定频道组发送消息
"""

class UserProfile(AbstractUser):
    genderoptions = (
        (1, '男'),
        (0, '女'),
    )
    identityOptions={
        (1,'董事长'),
        (2,'合伙人'),
        (3,'经理'),
        (4,'代理'),
        (5,'会员')
    }
    telephone = models.CharField(max_length=11)
    icon = models.ImageField(upload_to='icon', default='icon/default.png')
    password = models.CharField(max_length=100, null=True,blank=True,verbose_name='密码')
    nickname = models.CharField(max_length=20, null=True, blank=True,verbose_name='昵称')
    birthday = models.DateField(null=True, blank=True,verbose_name='生日')
    city = models.CharField(max_length=20, null=True, blank=True,verbose_name='城市')
    occupation= models.CharField(max_length=11, null=True, blank=True,verbose_name='职业')
    gender = models.SmallIntegerField(choices=genderoptions, default=1,verbose_name='性别')
    identity=models.IntegerField(choices=identityOptions,verbose_name='身份',default=5)
    balance=models.DecimalField(max_digits=10, decimal_places=2, verbose_name='余额',default=0)
    superiors=models.ForeignKey('self',on_delete=models.CASCADE,verbose_name='上级',null=True,blank=True)
    Invitation_code=models.CharField(max_length=100,verbose_name='邀请码',null=True,blank=True)
    is_staff = models.BooleanField(default=False, verbose_name='是否为员工')
    def save(self, *args, **kwargs):
        """
            重写保存方法实现余额变更检测
            1. 如果是更新操作（存在主键），获取旧的余额值进行比较
            2. 调用父类保存方法完成数据持久化
            3. 如果余额发生变化，触发通知机制
        """
        print('触发save信号')
        # 检查余额是否变化
        if self.pk: #判断是否为更新操作
            old_balance = UserProfile.objects.get(pk=self.pk).balance
            balance_changed = old_balance != self.balance
        else:
            balance_changed = False

        super().save(*args, **kwargs)  # 调用父类保存方法

        if balance_changed:
            self.notify_balance_change() # 如果余额发生变化，触发通知机制

    def notify_balance_change(self):
        """
            通过channels发送实时通知
            1. 获取channel_layer对象（连接redis）
            2. 使用async_to_sync将异步调用转换为同步
            3. 向特定用户组的websocket连接发送消息
             组名格式：balance_{user_id}
             事件类型对应consumer的blance_update方法
        """
        print('notify_balance_change触发')
        channel_layer = get_channel_layer() #获取通道层实例
        async_to_sync(channel_layer.group_send)(#异步转换为同步发送消息
            f'balance_{self.id}', #用户专属频道组名称
            {
                "type": "balance.update" #指定consumer处理函数的后缀
            #     可以添加额外数据，如：‘new_balance’:float(self.balance)
            }
        )



